package com.king.player.kingplayer.view;

import static com.king.player.kingplayer.AspectRatio.AR_16_9_FIT_PARENT;
import static com.king.player.kingplayer.AspectRatio.AR_4_3_FIT_PARENT;
import static com.king.player.kingplayer.AspectRatio.AR_ASPECT_FILL_PARENT;
import static com.king.player.kingplayer.AspectRatio.AR_ASPECT_FIT_PARENT;
import static com.king.player.kingplayer.AspectRatio.AR_MATCH_PARENT;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.PixelFormat;
import android.graphics.SurfaceTexture;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.os.Build;
import android.os.Bundle;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.TextureView;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewStub;
import android.widget.FrameLayout;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;

import com.king.player.kingplayer.AspectRatio;
import com.king.player.kingplayer.KingPlayer;
import com.king.player.kingplayer.source.DataSource;
import com.king.player.kingplayer.measure.IMeasureSurface;
import com.king.player.kingplayer.IPlayer;
import com.king.player.kingplayer.util.LogUtils;
import com.king.player.kingplayer.util.ScreenUtil;
import com.king.player.vlcplayer.VlcPlayer;
import com.ltwc.libplayer.R;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

/**
 * @author <a href="mailto:jenly1314@gmail.com">Jenly</a>
 */
public class VideoView extends FrameLayout implements IMeasureSurface, IPlayer<KingPlayer> {

    private View surfaceFrame;
    private KingSurfaceView surfaceVideo;
    private KingGLSurfaceView glSurfaceView;
    private KingTextureView textureVideo;

    private IMeasureSurface mMeasureSurface;

    private KingPlayer mPlayer;

    private boolean isSurfaceView;

    private boolean isSubtitlesGLSurface;

    private Surface mSurface;

    private KingPlayer.OnVideoSizeChangedListener mOnVideoSizeChangedListener;

    private KingPlayer.OnBufferingUpdateListener mOnBufferingUpdateListener;

    private KingPlayer.OnPlayerEventListener mOnPlayerEventListener;

    private KingPlayer.OnErrorListener mOnErrorListener;

    protected OnSurfaceListener mOnSurfaceListener;

    public VideoView(@NonNull Context context) {
        super(context);
        init(context, null, 0, 0);
    }

    public VideoView(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs, 0, 0);
    }

    public VideoView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs, defStyleAttr, 0);
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public VideoView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init(context, attrs, defStyleAttr, defStyleRes);
    }

    private void init(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        if (attrs != null) {
            TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.VideoView, defStyleAttr, defStyleRes);
            final int count = a.getIndexCount();
            for (int i = 0; i < count; i++) {
                int attr = a.getIndex(i);
                if (attr == R.styleable.VideoView_vvUseSurfaceView) {
                    isSurfaceView = a.getBoolean(attr, false);
                } else if (attr == R.styleable.VideoView_vvUseSubtitlesSurface) {
                    isSubtitlesGLSurface = a.getBoolean(attr, false);
                }
            }
            a.recycle();
        }
        inflate(context, R.layout.king_player_video_view, this);
        surfaceFrame = findViewById(R.id.surfaceFrame);
        //5.0以下版本强制使用TextureView渲染
        if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.N_MR1) {
            isSurfaceView = true;
            isSubtitlesGLSurface = false;
        }
        if (isSurfaceView) {
            ViewStub surfaceStub = surfaceFrame.findViewById(R.id.surfaceStub);
            surfaceVideo = surfaceStub != null ? (KingSurfaceView) surfaceStub.inflate() : (KingSurfaceView) surfaceFrame.findViewById(R.id.surfaceVideo);
            mMeasureSurface = surfaceVideo;
        } else if (isSubtitlesGLSurface) {
            ViewStub glSurfaceStub = surfaceFrame.findViewById(R.id.glSurfaceStub);
            glSurfaceView = glSurfaceStub != null ? (KingGLSurfaceView) glSurfaceStub.inflate() : (KingGLSurfaceView) surfaceFrame.findViewById(R.id.gl_surfaceVideo);
            glSurfaceView.setEGLContextClientVersion(2);   // GLContext 设置 OpenGLES2.0
            // 设置 renderer
            glSurfaceView.setRenderer(new GLRenderer());
            // 渲染方式，RENDERMODE_WHEN_DIRTY 表示被动渲染，只有在调用 requestRender 或者 onResume 等方法时才会进行渲染。
            // RENDERMODE_CONTINUOUSLY 表示持续渲染
            glSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
            mMeasureSurface = glSurfaceView;
        } else {
            ViewStub textureStub = surfaceFrame.findViewById(R.id.textureStub);
            textureVideo = textureStub != null ? (KingTextureView) textureStub.inflate() : (KingTextureView) surfaceFrame.findViewById(R.id.textureVideo);
            mMeasureSurface = textureVideo;
        }

    }


    public final void setPlayer(@NonNull KingPlayer player) {
        this.mPlayer = player;
        initSurface();
    }

    private void initSurface() {
        if (isSurfaceView) {
            surfaceVideo.getHolder().addCallback(new SurfaceHolder.Callback() {
                @Override
                public void surfaceCreated(SurfaceHolder holder) {
                    mSurface = holder.getSurface();
                    mPlayer.setSurface(holder);
                    mPlayer.updateSurface(surfaceVideo.getWidth(), surfaceVideo.getHeight());
                    if (mOnSurfaceListener != null) {
                        mOnSurfaceListener.onSurfaceCreated(mSurface, surfaceVideo.getWidth(), surfaceVideo.getHeight());
                    }
                }

                @Override
                public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
                    mPlayer.updateSurface(width, height);
                    if (mOnSurfaceListener != null) {
                        mOnSurfaceListener.onSurfaceSizeChanged(mSurface, width, height);
                    }
                }

                @Override
                public void surfaceDestroyed(SurfaceHolder holder) {
                    if (mOnSurfaceListener != null) {
                        mOnSurfaceListener.onSurfaceDestroyed(mSurface);
                    }
                    mPlayer.surfaceDestroy();
                }
            });
        } else {
            textureVideo.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {
                @Override
                public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
                    mSurface = new Surface(surface);
                    mPlayer.setSurface(mSurface);
                    mPlayer.updateSurface(width, height);
                    if (mOnSurfaceListener != null) {
                        mOnSurfaceListener.onSurfaceCreated(mSurface, width, height);
                    }
                }

                @Override
                public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
                    mPlayer.updateSurface(width, height);
                    if (mOnSurfaceListener != null) {
                        mOnSurfaceListener.onSurfaceSizeChanged(mSurface, width, height);
                    }
                }

                @Override
                public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
                    if (mOnSurfaceListener != null) {
                        mOnSurfaceListener.onSurfaceDestroyed(mSurface);
                    }
                    mPlayer.surfaceDestroy();
                    return true;
                }

                @Override
                public void onSurfaceTextureUpdated(SurfaceTexture surface) {

                }
            });
        }

        addListener();
    }

    public void setOnVideoSizeChangedListener(KingPlayer.OnVideoSizeChangedListener listener) {
        mOnVideoSizeChangedListener = listener;
    }

    public void setOnBufferingUpdateListener(KingPlayer.OnBufferingUpdateListener listener) {
        this.mOnBufferingUpdateListener = listener;
    }

    public void setOnPlayerEventListener(KingPlayer.OnPlayerEventListener listener) {
        this.mOnPlayerEventListener = listener;
    }

    public void setOnErrorListener(KingPlayer.OnErrorListener listener) {
        this.mOnErrorListener = listener;
    }

    /**
     * 添加监听事件
     */
    private void addListener() {
        mPlayer.setOnVideoSizeChangedListener(new KingPlayer.OnVideoSizeChangedListener() {
            @Override
            public void onVideoSizeChanged(int videoWidth, int videoHeight) {
                setVideoSize(videoWidth, videoHeight);
                if (mOnVideoSizeChangedListener != null) {
                    mOnVideoSizeChangedListener.onVideoSizeChanged(videoWidth, videoHeight);
                }
            }
        });
        mPlayer.setOnBufferingUpdateListener(new KingPlayer.OnBufferingUpdateListener() {
            @Override
            public void onBufferingUpdate(int percent) {
                if (mOnBufferingUpdateListener != null) {
                    mOnBufferingUpdateListener.onBufferingUpdate(percent);
                }
            }
        });

        mPlayer.setOnPlayerEventListener(new KingPlayer.OnPlayerEventListener() {
            @Override
            public void onEvent(int event, Bundle bundle) {
                if (mOnPlayerEventListener != null) {
                    mOnPlayerEventListener.onEvent(event, bundle);
                }
            }
        });

        mPlayer.setOnErrorListener(new KingPlayer.OnErrorListener() {
            @Override
            public void onErrorEvent(int event, @Nullable Bundle bundle) {
                LogUtils.e("onErrorEvent" + event + "------" + mOnErrorListener);
                if (mOnErrorListener != null) {
                    mOnErrorListener.onErrorEvent(event, bundle);
                }
            }
        });
    }

    public int getSurfaceWidth() {
        return mMeasureSurface.getMeasuredWidth();
    }

    public int getSurfaceHeight() {
        return mMeasureSurface.getMeasuredHeight();
    }

    @Override
    public void setVideoSize(int videoWidth, int videoHeight) {
        mMeasureSurface.setVideoSize(videoWidth, videoHeight);
    }

    @Override
    public void setVideoSampleAspectRatio(int videoSarNum, int videoSarDen) {
        mMeasureSurface.setVideoSampleAspectRatio(videoSarNum, videoSarDen);
    }

    @Override
    public void setVideoRotation(int videoRotationDegree) {
        mMeasureSurface.setVideoRotation(videoRotationDegree);
    }

    @Override
    public void setAspectRatio(@AspectRatio int aspectRatio) {
        mMeasureSurface.setAspectRatio(aspectRatio);
        if (mPlayer != null && mPlayer instanceof VlcPlayer) {
            switch (aspectRatio) {
                case AR_ASPECT_FILL_PARENT:
                case AR_MATCH_PARENT:
                    ((VlcPlayer) mPlayer).setAspectRatio(ScreenUtil.getScreenWith(getContext()) + ":" + ScreenUtil.getScreenHeight(getContext()));
                    break;
                case AR_16_9_FIT_PARENT:
                    ((VlcPlayer) mPlayer).setAspectRatio("16:9");
                    break;
                case AR_4_3_FIT_PARENT:
                    ((VlcPlayer) mPlayer).setAspectRatio("4:3");
                    break;
                default:
                    ((VlcPlayer) mPlayer).setAspectRatio(null);
                    break;
            }
        }
    }

    @Override
    public void updateVideoSurface() {
        mMeasureSurface.updateVideoSurface();
    }

    private DataSource dataSource;

    @Override
    public void setDataSource(@NonNull DataSource dataSource) {
        if (mPlayer != null) {
            this.dataSource = dataSource;
            mPlayer.setDataSource(dataSource);
        }
    }

    public DataSource getDataSource() {
        return dataSource;
    }

    public void setHWEnable(boolean HWEnable) {
        if (mPlayer != null && mPlayer instanceof VlcPlayer) {
            ((VlcPlayer) mPlayer).setHWEnable(HWEnable);
        }
    }

    @Override
    public void start() {
        mPlayer.start();
    }

    @Override
    public void pause() {
        mPlayer.pause();
    }

    @Override
    public void stop() {
        this.postDelayed(new Runnable() {
            @Override
            public void run() {
                mPlayer.stop();
            }
        }, 0);

    }

    @Override
    public void release() {
        mPlayer.release();
    }

    @Override
    public void reset() {
        mPlayer.reset();
    }

    @Override
    public boolean isPlaying() {
        return mPlayer.isPlaying();
    }

    @Override
    public int getPlayerState() {
        return mPlayer.getPlayerState();
    }

    @Override
    public void setVolume(float volume) {
        mPlayer.setVolume(volume);
    }


    @Override
    public void seekTo(int msec) {
        mPlayer.seekTo(msec);
    }

    @Override
    public int getCurrentPosition() {
        return mPlayer.getCurrentPosition();
    }

    @Override
    public int getDuration() {
        return mPlayer.getDuration();
    }

    @Override
    public void setSpeed(float speed) {
        mPlayer.setSpeed(speed);
    }

    @Override
    public float getSpeed() {
        return mPlayer.getSpeed();
    }

    @Override
    public void setLooping(boolean looping) {
        mPlayer.setLooping(looping);
    }

    @Override
    public boolean isLopping() {
        return mPlayer.isLopping();
    }

    @Override
    public float getBufferPercentage() {
        return mPlayer.getBufferPercentage();
    }

    @Override
    public KingPlayer getPlayer() {
        return mPlayer;
    }

    public int getVideoHeight() {
        return mPlayer.getVideoWidth();
    }

    public int getVideoWidth() {
        return mPlayer.getVideoHeight();
    }

    public void setOnSurfaceListener(OnSurfaceListener listener) {
        mOnSurfaceListener = listener;
    }

    public interface OnSurfaceListener {
        void onSurfaceCreated(Surface surface, int width, int height);

        void onSurfaceSizeChanged(Surface surface, int width, int height);

        void onSurfaceDestroyed(Surface surface);
    }

    final class GLRenderer implements GLSurfaceView.Renderer {

        @Override
        public void onSurfaceCreated(GL10 gl, EGLConfig config) {
            Log.e("AA", "GLRenderer onSurfaceCreated");
            // 关闭抗抖动
            gl.glDisable(GL10.GL_DITHER);
            // 设置系统对透视进行修正
            gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);
            //gl.glClearColor(0, 0, 0, 0);
        }

        @Override
        public void onSurfaceChanged(GL10 gl, int width, int height) {
            Log.e("AA", "GLRenderer onSurfaceChanged");
            // 渲染窗口大小发生改变或者屏幕方法发生变化时候回调
            GLES20.glViewport(0, 0, width, height);
        }

        @Override
        public void onDrawFrame(GL10 gl) {
            //Log.e("AA","GLRenderer onDrawFrame");
            // 执行渲染工作
            //GLES20.glClearColor(GLES20.GL_COLOR_BUFFER_BIT, 0f, 0f, 0f);
        }
    }
}
